package grex;

/**
 * <p>Title: Environment</p>
 * <p>Description: Loser in en fil och tillhandaholler metoder for att mojligora
 * otkomst av troning,test och valideringsmongd. All data skall liga i samma fil
 * Filen skall ha foljande format:
 * TYP,desierd,input1,...,inputN.
 * TYP: or en av TRAIN/VAL/TEST eller anvondar definierad. Kolumnerna kan
 * separeras med (" " ; , \t).  "." anvonds som decimalavdelare </p>
 * <p>Copyright: Rikard Konig Copyright (c) 2003</p>
 * <p>Company: Hogskolan i Boros</p>
 * @author not attributable
 * @version 1.0
 */
import grex.Nodes.KnnNeighbour;
import grex.Data.PredictionContainer;
import grex.Data.ArffTableModel;
import grex.fitnessfunctions.ErrorFunctions.ErrorCalculator;
import grex.Nodes.GeneException;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.TreeSet;

public class Environment implements Serializable {
  private GPFactory bnf;
  private double[][] selectionSet;

  public  int[] columnType;
  private Options options;
  private ArffTableModel data;
  private ErrorCalculator errorCalculator;

  public Environment(String DataFileName, String BNFFileName) throws IOException, BNFException, GeneException {
        //Ingen bnf har valts av anvondaren
        if (BNFFileName.equalsIgnoreCase("")) {
            BNFFileName = chooseBNF();
        }
        
        options = bnf.getOptions();
        data= new ArffTableModel(DataFileName);
        initProblemType();
        bnf = new GPFactory(BNFFileName,this);
    }
  public Environment(ArffTableModel model,Options options) throws IOException, BNFException{
        data= model;
        this.options = options;
 //       initProblemType();
        bnf = new GPFactory(options,this);
  }

  public Environment(Options options) throws IOException, BNFException {
        data= new ArffTableModel(options.getDATA_FILE(), options.getNR_OF_FOLDS(),options.getFOLD_SEED());
        if (options.getBNF_FILE().equalsIgnoreCase("")) {
            options.setBNF_FILE(chooseBNF());
        }
        this.options = options;
        initProblemType();
        bnf = new GPFactory(options,this);
    }
  public ErrorCalculator getErrorCalculator(){
      if(errorCalculator == null)
          errorCalculator = new ErrorCalculator(this);
      return errorCalculator;
  }
  public String getPredictorClass(){
      return bnf.getPredictorClass();
  }
  public ArrayList<String> getFolds(){
      return getData().getFolds();
  }
  public ArrayList<KnnNeighbour> getKNNs(double[] instance,int k){
      return getData().getKNN(instance, k,options.getTestFOLD());
  }
  
  public TreeSet<KnnNeighbour> getKNNs(double[] instance,PredictionContainer neighours){
      return getData().getKNN(instance,neighours);
  }  

  public Environment(String DataFileName, String BNFFileName, double train,
                     double val, double test) throws IOException, BNFException {
    if(BNFFileName.equalsIgnoreCase("")){
      BNFFileName = chooseBNF();
    }

     options = bnf.getOptions();     
     data= new ArffTableModel(DataFileName);
     initProblemType();
     bnf = new GPFactory(BNFFileName,this);
  }

    
  public double[] getMaxValues(){
      return getData().getTrainMaxValues(options.getTestFOLD());
  }
  public double getMaxTrainTarget(){
      double[] d = getData().getTrainMaxValues(options.getTestFOLD());
      return d[d.length-1];
  }
  
  public double getMinTrainTarget(){
      double[] d = getData().getTrainMinValues(options.getTestFOLD());
      return d[d.length-1];
  }
  public double[] getMinValues(){
      return getData().getTrainMinValues(options.getTestFOLD());
  }
  
  public int getRandomCategoricalColumnIndex(){
     return getData().getRandomCategoricalInputColumn();              
  }
  public int getNrOfCategoricalColumns(){
      return getData().getNrOfCategorialColumns();
  }

  public int getNrOfContinuousColumns(){
      return getData().getNrOfContinousColumns();
  }

  public boolean isNumericColumn(int colIndex){
      return getData().getContinuousColumns()[colIndex];
  }
  
  public int getRandomContiousColumnIndex() throws GeneException{
     return getData().getRandomContinuousInputColumn();              
  }

  /*Only used when predicting probabillities*/
  public int getRandomProbContiousColumnIndex() throws GeneException{
     return getData().getRandomProbContinuousInputColumn();
  }
  
  public double getRandomTargetValue(){
      return getData().getRandomTargetValue(options.getTestFOLD());                      
  }
    public String getRealClassValue(int column,double classInternalValue){
        return getData().getRealCategerocialValue(column, classInternalValue);
    }
    
     public String getRealTargetClassValue(double classInternalValue){
        return getData().getRealTargetClassValue(classInternalValue);
    }
  public Options getOptions(){
      return options;
  }
  public void initProblemType(){
    if( getData().isClassificationTask())
      options.setPROBLEM_TYPE(Options.CLASSIFICATION);
    else
      options.setPROBLEM_TYPE(Options.REGRESSION);
  }

  private String chooseBNF(){
    if(!data.isClassificationTask()) {
      options.setPROBLEM_TYPE(Options.REGRESSION);
      //det finns endast kontinuerliga variabler
      if(   getData().getNrOfCategorialColumns() ==0){
        return "bnf_if_reg_con_free.txt";
      }else if (getData().getNrOfCategorialColumns() >0 && getData().getNrOfContinousColumns()!=0){
        return "bnf_if_reg_cat_con.txt";
      }else{
        return "bnf_if_reg_cat.txt";
      }
    }else{
      options.setPROBLEM_TYPE(Options.CLASSIFICATION);
      int nrOfCat=getData().getNrOfCategorialColumns();
      if ( (nrOfCat == 0)) {//Om det bara finns kontinuerliga variabler
        //om det bara finns tvo klasser
        if (    getData().getNrOfTargetCategories() == 2) {
          //return "bnf_and_or_con.txt"; obs fix byt tillbaks
          return "bnf_if_con.txt";
        }
        else {
          return "bnf_if_con.txt";
        }
        //Det finns kategoriska och kontunielriga variabler
      }
      else if(nrOfCat >0 && getData().getNrOfContinousColumns()!=0){
        //Om det bara finns tvo klasser
        if (    getData().getNrOfTargetCategories() == 2) {
          return "bnf_if_cat_con.txt";
//          return "bnf_and_or_cat_con.txt"; Byt tbax
        }
        else {
          return "bnf_if_cat_con.txt";
        }
      } else{
        //Det finns bara kontinuerliga variabler
        //Om det bara finns tvo klasser
        if (    getData().getNrOfTargetCategories() == 2) {
         // return "bnf_and_or_cat.txt"; byt tbax
         return "bnf_if_cat.txt";
        }
        else {
          return "bnf_if_cat.txt";
        }
      }
    }
  }

  public GPFactory getBNF() {
    return bnf;
  }
  public int getNumberOfSplits(int column, String fold){
      return getData().getNumberOfSplits(column, fold);
  }

  public double getInternalNumericalValue(int column,double internalValue,String fold){
      return getData().getGeneNumericalValue(column, internalValue, fold);
  }

  public double getInternalNumericalValue(int column,double internalValue){
      return getData().getGeneNumericalValue(column, internalValue, options.getTestFOLD());
  }

    public double getInternalCategoryValue(int catColumn,String category){
      return getData().calcInternalCategoryValue(catColumn, category);
  }

  public int getTargetColumnIndex() {
    return getData().getTargetColumnIndex();
  }
  
  public int getNrOfTargetCategories() {
    return getData().getNrOfTargetCategories();
  }
  
  public void initFold(String fold){
        getData().initFold(fold);

  }
  
  IPredictiveModel exctractionModel;
  public void setExtractoinModel(IPredictiveModel model){
      exctractionModel = model;
      
  }
  
  public double[][] getTrainData() {
    return getData().getTrainFold(options.getTestFOLD());
  }

  public double[][] getTestData() {
    return getData().getTestFold(options.getTestFOLD());
  }

  public double[][] getValData() {
      return getData().getValFold(options.getTestFOLD());    
  }
  
  public boolean hasValidationSet(){
      return getData().getValFold(options.getTestFOLD()).length>0;    
  }

    public String[] getVariableNames(){
        return getData().getColumnNames();
    }
    /*public int getRandomNonProbContiousColumnIndex() throws GeneException{
         return getData().getRandomNonProbContinuousInputColumn();
    }//*/



    public double[][] getSelectionSet() {
        return selectionSet;
    }

    public void setSelectionSet(double[][] selectionSet) {
        this.selectionSet = selectionSet;
    }

    public ArffTableModel getData() {
        return data;
    }

    public void setData(ArffTableModel data) {
        this.data = data;
    }

}
